LL_I3C_Init and LL_I3C_DeInit APIs migration

The LL initialization and de-initialization functions previously available in the stm32tnxx_ll_i3c.c files within HAL1 are no longer present in HAL2. In HAL2, all LL C files ( stm32tnxx_ll_i3c.c) have been removed, leaving only the LL header files ( stm32tnxx_ll_i3c.h) that contain static inline functions.

If users need to initialize or de-initialize I3C using the LL layer, they have two methods:

  • Utilize STM32CubeMX2 Code Generation: Rely on STM32CubeMX2 to generate code with the LL layer for I3C initialization and de-initialization.

  • Replace manually the initialization and de-initialization functionsReplace the LL_I3C_Init and LL_I3C_DeInit functions

    manually with equivalent sequences using the static inline functions provided in the stm32tnxx_ll_i3c.h file, tailored to their specific configuration and requirements.

This approach ensures that the initialization and de-initialization sequences are precisely addressing the given use case based on the LL static inline functions provided in the stm32tnxx_ll_i3c.h header file. The sequences offer improved footprint optimization compared to the previous LL initialization functions found in stm32tnxx_ll_i3c.c.

Related concept: Remove stm32tnxx_ll_ppp.c files

Method 1: Utilize STM32CubeMX2 Code Generation

LL I3C configuration panel

Create a new project with the STM32CubeMX2, then start the initialization and the main configuration.

Project configuration panel

LL I3C main features configuration

Configure the I3C main features.

I3C main feature configuration

LL I3C advanced features configuration

Configure the advanced I3C features.

I3C advanced feature configuration

GPIO configuration

Configure GPIO pins.

I3C GPIO configuration

DMA configuration

Configure the DMA for data reception as needed.

DMA TX configuration

I3C DMA TX configuration

DMA RX configuration

I3C DMA RX configuration

DMA TC configuration

I3C DMA TC configuration

NVIC configuration

Configure the NVIC in case of an interrupt.

I3C NVIC configuration

Generated I3C initialization sequences

The I3C initialization sequence is generated in the mx_i3c1_init function in mx_i3c1.c file under $YOUR_PROJECT_NAME$/$YOUR_PROJECT_NAME$_SW/generated/STM32Cube_CodeGen.

Related concepts:

STM32CubeMX2 Generated : I3C initialization and de-initialization sequences

Topic

Code Snippet HAL1

Code Snippet HAL2

Initialization and configuration sequence

static void MX_I3C1_Init(void)
{
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

  /** Initializes the peripherals clock  */
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I3C1;
  PeriphClkInitStruct.I3c1ClockSelection = RCC_I3C1CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I3C1);

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOF);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_15;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOF, &GPIO_InitStruct);

  /* I3C1 interrupt Init */
  NVIC_SetPriority(I3C1_EV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(I3C1_EV_IRQn);
  NVIC_SetPriority(I3C1_ER_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(I3C1_ER_IRQn);

  /** I3C Initialization*/
  LL_I3C_SetMode(I3C1, LL_I3C_MODE_CONTROLLER);
  LL_I3C_SetDataHoldTime(I3C1, LL_I3C_SDA_HOLD_TIME_0_5);
  LL_I3C_SetControllerActivityState(I3C1, LL_I3C_OWN_ACTIVITY_STATE_0);
  LL_I3C_ConfigClockWaveForm(I3C1, 0x00774f77);
  LL_I3C_SetCtrlBusCharacteristic(I3C1, 0x003100f8);
  LL_I3C_DisableHJAck(I3C1);

  /** Configure FIFO */
  LL_I3C_SetRxFIFOThreshold(I3C1, LL_I3C_RXFIFO_THRESHOLD_1_4);
  LL_I3C_SetTxFIFOThreshold(I3C1, LL_I3C_TXFIFO_THRESHOLD_1_4);
  LL_I3C_DisableControlFIFO(I3C1);
  LL_I3C_DisableStatusFIFO(I3C1);

  /** Configure Controller */
  LL_I3C_SetOwnDynamicAddress(I3C1, 0);
  LL_I3C_EnableOwnDynAddress(I3C1);
  LL_I3C_SetStallTime(I3C1, 0x00);
  LL_I3C_DisableStallACK(I3C1);
  LL_I3C_DisableStallParityCCC(I3C1);
  LL_I3C_DisableStallParityData(I3C1);
  LL_I3C_DisableStallTbit(I3C1);
  LL_I3C_DisableHighKeeperSDA(I3C1);

   /** Enable the selected I3C peripheral */
  LL_I3C_Enable(I3C1);
  }
I3C_TypeDef *mx_i3c1_init(void)
{
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I3C1);

  LL_RCC_SetI3CClockSource(LL_RCC_I3C1_CLKSOURCE_PCLK1);

  /* Set the controller mode */
  LL_I3C_SetMode(I3C1, LL_I3C_MODE_CONTROLLER);

  LL_I3C_ConfigClockWaveForm(I3C1, 0x120101U);
  LL_I3C_SetBusCharacteristic(I3C1, 0xA002EU);

  /* Set the FIFO configuration */
  LL_I3C_ConfigCtrlFifo(I3C1, LL_I3C_RXFIFO_THRESHOLD_1_8, LL_I3C_TXFIFO_THRESHOLD_1_8, LL_I3C_CTRL_FIFO_NONE);

  /* GPIO Clocks activation */
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

  /* Configure IO output speed (Low, Medium, High or Very-High) */
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_8, LL_GPIO_SPEED_FREQ_HIGH);

  /* Configure IO output type (Push-Pull or Open-Drain) */
  LL_GPIO_SetPinOutputType(GPIOA, LL_GPIO_PIN_9 | LL_GPIO_PIN_8, LL_GPIO_OUTPUT_PUSHPULL);

  /* Activate the Pull-up, Pull-down resistor, or No pull for the current IO */
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_9, LL_GPIO_PULL_NO);
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_8, LL_GPIO_PULL_NO);

  /* Configure the Alternate Function in current IO */
  LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_2);
  LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_8, LL_GPIO_AF_2);

  /* Configure IO direction mode (Input, Output, Alternate or Analog) */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_8, LL_GPIO_MODE_ALTERNATE);

  /* Enable the Event interrupt for I3C1 */
  NVIC_SetPriority(I3C1_EV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
  NVIC_EnableIRQ(I3C1_EV_IRQn);

  /* Enable the Error interrupt for I3C1 */
  NVIC_SetPriority(I3C1_ERR_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
  NVIC_EnableIRQ(I3C1_ERR_IRQn);

  return I3C1;
 }

Method 2: Manually replace the initialization and de-initialization functions

LL_I3C_Init() API migration

According to the use-case, implement the precise sequence call based on the LL static inline functions provided in the stm32tnxx_ll_i3c.h header file.

I3C Mode Comparison between HAL1 and HAL2

HAL1

HAL2

Case of I3C in mode CONTROLLER

LL_I3C_InitTypeDef i3c_InitStruct;

i3c_InitStruct.CtrlBusCharacteristic.SDAHoldTime         = LL_I3C_SDA_HOLD_TIME_0_5;
i3c_InitStruct.CtrlBusCharacteristic.WaitTime            = LL_I3C_OWN_ACTIVITY_STATE_0;
i3c_InitStruct.CtrlBusCharacteristic.SCLPPLowDuration    = 1U;
i3c_InitStruct.CtrlBusCharacteristic.SCLI3CHighDuration  = 2U;
i3c_InitStruct.CtrlBusCharacteristic.SCLODLowDuration    = 3U;
i3c_InitStruct.CtrlBusCharacteristic.SCLI2CHighDuration  = 4U;
i3c_InitStruct.CtrlBusCharacteristic.BusFreeDuration     = 5U;
i3c_InitStruct.CtrlBusCharacteristic.BusIdleDuration     = 6U;
i3c_InitStruct.TgtBusCharacteristic.BusAvailableDuration = 7U;

LL_I3C_Init(I3C1, &i3c_InitStruct, LL_I3C_MODE_CONTROLLER);
LL_I3C_SetMode(I3C1, LL_I3C_MODE_CONTROLLER);
uint32_t waveform_value = (1U
                           | (2U << I3C_TIMINGR0_SCLH_I3C_Pos)
                           | (3U << I3C_TIMINGR0_SCLL_OD_Pos)
                           | (4U << I3C_TIMINGR0_SCLH_I2C_Pos));
LL_I3C_ConfigClockWaveForm(I3C1, waveform_value);
uint32_t timing_value = (LL_I3C_SDA_HOLD_TIME_0_5
                         | LL_I3C_OWN_ACTIVITY_STATE_0
                         | (5U << I3C_TIMINGR1_FREE_Pos)
                         | 6U);
LL_I3C_SetCtrlBusCharacteristic(I3C1, timing_value);

Case of I3C in mode TARGET

LL_I3C_InitTypeDef i3c_InitStruct;

i3c_InitStruct.CtrlBusCharacteristic.SDAHoldTime         = LL_I3C_SDA_HOLD_TIME_0_5;
i3c_InitStruct.CtrlBusCharacteristic.WaitTime            = LL_I3C_OWN_ACTIVITY_STATE_0;
i3c_InitStruct.CtrlBusCharacteristic.SCLPPLowDuration    = 1U;
i3c_InitStruct.CtrlBusCharacteristic.SCLI3CHighDuration  = 2U;
i3c_InitStruct.CtrlBusCharacteristic.SCLODLowDuration    = 3U;
i3c_InitStruct.CtrlBusCharacteristic.SCLI2CHighDuration  = 4U;
i3c_InitStruct.CtrlBusCharacteristic.BusFreeDuration     = 5U;
i3c_InitStruct.CtrlBusCharacteristic.BusIdleDuration     = 6U;
i3c_InitStruct.TgtBusCharacteristic.BusAvailableDuration = 7U;

LL_I3C_Init(I3C1, &i3c_InitStruct, LL_I3C_MODE_TARGET);
LL_I3C_SetMode(I3C1, LL_I3C_MODE_TARGET);
LL_I3C_SetTgtBusCharacteristic(I3Cx, 7U);

LL_I3C_DeInit() API migration

According to the used I3C1, Implement the precise calls to LL_APB1_GRP1_ForceReset() and LL_APB1_GRP1_ReleaseReset()

Comparison of HAL1 and HAL2

HAL1

HAL2

LL_I3C_DeInit(I3C1)
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_I3C1);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_I3C1);